package com.matrix.order.domain.model;

import com.matrix.api.product.ProductApi;
import com.matrix.common.enums.OrderStatusEnum;
import com.matrix.common.exception.BusinessException;
import com.matrix.order.infrastructure.gateway.acl.MarketingAcl;
import com.matrix.order.infrastructure.gateway.acl.PaymentAcl;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.rpc.RpcException;
import org.springframework.util.CollectionUtils;

import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author 有点甜
 * @since 2025/7/27
 */
@Data
@Slf4j
public class Order implements Serializable {
    @Serial
    private static final long serialVersionUID = 1L;

    private Long id;
    private String orderNo;

    private List<OrderItem> items = new ArrayList<>();
    private List<OrderPayment> payments = new ArrayList<>();

    private Long userId;
    private Long shopId;
    private Long shopOwnerId;
    private BigDecimal originalAmount;
    private BigDecimal discountAmount;
    private BigDecimal actualAmount;
    private Integer tablewareQuantity;
    private String remark;
    private String areaSeat;
    private OrderStatusEnum status;
    private LocalDateTime paymentTime;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;

    private Long userCouponId;
    private Long merchantCouponId;

    public Order() {
    }

    @DubboReference(check = false)
    private ProductApi productApi;

    public void paymentSuccess(BigDecimal paidAmount) {
        if (this.status != OrderStatusEnum.PENDING_PAYMENT) {
            log.warn("订单 {} 状态不为“待支付”, 可能已处理, 跳过支付成功逻辑", this.orderNo);
            return;
        }

        if (paidAmount.compareTo(this.actualAmount) != 0) {
            log.error("订单 {} 金额不匹配！数据库金额: {}, 支付金额: {}", this.orderNo, this.actualAmount, paidAmount);
            throw new BusinessException("支付金额不匹配");
        }

        this.status = OrderStatusEnum.PENDING_ACCEPTANCE;
        this.paymentTime = LocalDateTime.now();
        this.updateTime = LocalDateTime.now();
    }

    public void accept(Long shopId) {
        if (!this.shopId.equals(shopId)) {
            throw new BusinessException("无权操作此订单");
        }
        if (!this.status.canAccept()) {
            throw new BusinessException("订单当前状态无法接单");
        }
        this.status = OrderStatusEnum.IN_PROGRESS;
        this.updateTime = LocalDateTime.now();
    }

    public void reject(Long shopId, String reason, PaymentAcl paymentAcl) {
        if (!this.shopId.equals(shopId)) {
            throw new BusinessException("无权操作此订单");
        }

        if (this.status == OrderStatusEnum.PENDING_ACCEPTANCE) {
            paymentAcl.requestRefund(this, this.actualAmount, reason != null ? reason : "商家拒单");
        } else if (this.status == OrderStatusEnum.PENDING_PAYMENT) {
            paymentAcl.closePayment(this.orderNo);
        } else {
            throw new BusinessException("订单当前状态无法拒单");
        }

        this.status = OrderStatusEnum.CANCELLED;
        this.remark = (this.remark != null ? this.remark : "") + " [商家拒单原因: " + reason + "]";
        this.updateTime = LocalDateTime.now();
        releaseStock();
    }

    public void finishProduction(Long shopId) {
        if (!this.shopId.equals(shopId)) {
            throw new BusinessException("无权操作此订单");
        }
        if (!this.status.canFinishProduction()) {
            throw new BusinessException("订单当前状态无法变更为制作完成");
        }
        this.status = OrderStatusEnum.WAITING_FOR_SERVING;
        this.updateTime = LocalDateTime.now();
    }

    public void startServing(Long shopId) {
        if (!this.shopId.equals(shopId)) {
            throw new BusinessException("无权操作此订单");
        }
        if (!this.status.canStartServing()) {
            throw new BusinessException("订单当前状态无法开始上菜");
        }
        this.status = OrderStatusEnum.SERVING;
        this.updateTime = LocalDateTime.now();
    }

    public void finishServing(Long shopId) {
        if (!this.shopId.equals(shopId)) {
            throw new BusinessException("无权操作此订单");
        }
        if (!this.status.canFinishServing()) {
            throw new BusinessException("订单当前状态无法完成上菜");
        }
        this.status = OrderStatusEnum.SERVING_COMPLETED;
        this.updateTime = LocalDateTime.now();
    }

    public void finishMeal(Long userId) {
        if (!this.userId.equals(userId)) {
            throw new BusinessException("无权操作此订单");
        }
        if (!this.status.canFinishMeal()) {
            throw new BusinessException("订单当前状态无法结束用餐");
        }
        this.status = OrderStatusEnum.PENDING_REVIEW;
        this.updateTime = LocalDateTime.now();
    }

    public void markAsReviewed() {
        if (this.status != OrderStatusEnum.PENDING_REVIEW) {
            log.warn("Attempted to mark a non-reviewable order as reviewed. OrderId: {}", this.id);
            return;
        }
        this.status = OrderStatusEnum.COMPLETED;
        this.updateTime = LocalDateTime.now();
    }

    public void timeoutClose(PaymentAcl paymentAcl) {
        if (this.status == OrderStatusEnum.PENDING_PAYMENT) {
            this.status = OrderStatusEnum.CANCELLED;
            this.remark = (this.remark != null ? this.remark : "") + " [支付超时自动关闭]";
            this.updateTime = LocalDateTime.now();
            paymentAcl.closePayment(this.orderNo);
            releaseCoupons(null);
            releaseStock();
        }
    }

    public List<OrderItem> requestCancelDishes(Long userId, List<Long> itemIds) {
        if (!this.userId.equals(userId)) {
            throw new BusinessException("无权操作此订单");
        }
        if (!this.status.canAddOrCancelDish()) {
            throw new BusinessException(this.status.getCannotAddOrCancelDishMessage());
        }

        List<OrderItem> canceledItems = new ArrayList<>();
        for (Long itemId : itemIds) {
            OrderItem item = findItemById(itemId);
            item.markForCancellation();
            canceledItems.add(item);
        }
        return canceledItems;
    }

    public BigDecimal approveCancelDish(Long shopId, Long orderItemId) {
        if (!this.shopId.equals(shopId)) {
            throw new BusinessException("无权操作此订单");
        }
        OrderItem item = findItemById(orderItemId);
        item.approveCancellation();

        BigDecimal refundAmount = item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity()));
        this.actualAmount = this.actualAmount.subtract(refundAmount);
        this.originalAmount = this.originalAmount.subtract(refundAmount);
        this.updateTime = LocalDateTime.now();

        return refundAmount;
    }

    public void rejectCancelDish(Long shopId, Long orderItemId) {
        if (!this.shopId.equals(shopId)) {
            throw new BusinessException("无权操作此订单");
        }
        OrderItem item = findItemById(orderItemId);
        item.rejectCancellation();
    }


    public OrderItem findItemById(Long itemId) {
        return this.items.stream()
                .filter(item -> item.getId().equals(itemId))
                .findFirst()
                .orElseThrow(() -> new BusinessException("订单项不存在"));
    }

    public void addPayment(OrderPayment payment) {
        if (this.payments == null) {
            this.payments = new ArrayList<>();
        }
        this.payments.add(payment);
    }

    public void addNewItems(List<OrderItem> newItems) {
        if (CollectionUtils.isEmpty(newItems)) {
            return;
        }
        BigDecimal addedAmount = newItems.stream()
                .map(item -> item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity())))
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        this.originalAmount = this.originalAmount.add(addedAmount);
        this.actualAmount = this.actualAmount.add(addedAmount);
        this.updateTime = LocalDateTime.now();

        this.items.addAll(newItems);
    }

    public void releaseCoupons(MarketingAcl marketingAcl) {
        if (this.userCouponId != null && this.userCouponId > 0) {
            marketingAcl.releaseCoupon(this.userCouponId);
        }
        if (this.merchantCouponId != null && this.merchantCouponId > 0) {
            marketingAcl.releaseCoupon(this.merchantCouponId);
        }
    }

    private void releaseStock() {
        if (items.isEmpty()) {
            return;
        }
        Map<Long, Integer> stockIncreaseMap = items.stream()
                .filter(item -> item.getStatus() == 0)
                .collect(Collectors.toMap(OrderItem::getProductId, OrderItem::getQuantity, Integer::sum));

        if (!stockIncreaseMap.isEmpty()) {
            try {
                productApi.increaseStock(stockIncreaseMap);
            } catch (RpcException e) {
                log.error("订单 {} 取消时返还库存失败,需要手动处理 Details: {}", this.orderNo, e.getMessage());
            }
        }
    }
}